 |
 |
|
 |
 |
 |
 |
|
 |
 |
KazMuzik Blog のオフィシャルサイトは、KazMuzik.net に引越しました。KazMuzik Blog official site was moved to KazMuzik.netTags: american_life, caltrain, computer_technology, español, français, game, health, immigration, internet, japanese, jobs_in_america, music, music_and_computer, music_gear, music_technology, programming, rebate, recycle_and_donation, second_life, tax, test, useful_link, walking
|
 |
 |
 |
 |
|
 |
 |

 |
|
 |
 |
 |
 |
|
 |
 |
1年前には、Nutch (0.9) を利用して、このブログのエントリをすべて fetch して、以降は、同様に差分だけを fetch して、これらの HTML をコンバートして、kazmuzik.net/lj を作成していました。しかし、各エントリのページだけならよいのですが、Tag のページや最新の 20エントリを含むページなども、その都度、fetch してコンバートしていたので、かなり無駄な作業をしていました。効率化する構想はずっとあったのですが、つい延ばし延ばしになっていました。今回は、web hosting service を利用し始めたので、本格的にブログを移行するため、本格的に手を入れることにしました。 まずは、各エントリページの fetch の部分を curl を用いることにしました。以前は Nutch を使っていたものの、depth=1 で、seeds のページだけを fetch していたので、crawler としては活用していませんでしたし、Hadoop ファイルシステムにデータがあったので、扱いが面倒になっていました。今回は curl によるシンプルな fetch として、各エントリごとに、ひとつのファイルとします。 その前に、自分のエントリの ID をすべて得ておく必要があります。これには、月ごとのページを利用することにします。例えば、今月のページは、 http://kazuomik.livejournal.com/2009/05/ ですが、これから今月のエントリの ID をすべて得ることができます。このブログは 2006年から始めたので、それ以降の月のページをすべて curl で fetch します。
$ curl http://kazuomik.livejournal.com/[2006-2009]/[01-12]/ -o "#1-#2.html"
$ ls
2006-01.html 2006-11.html 2007-09.html 2008-07.html 2009-05.html
2006-02.html 2006-12.html 2007-10.html 2008-08.html 2009-06.html
2006-03.html 2007-01.html 2007-11.html 2008-09.html 2009-07.html
2006-04.html 2007-02.html 2007-12.html 2008-10.html 2009-08.html
2006-05.html 2007-03.html 2008-01.html 2008-11.html 2009-09.html
2006-06.html 2007-04.html 2008-02.html 2008-12.html 2009-10.html
2006-07.html 2007-05.html 2008-03.html 2009-01.html 2009-11.html
2006-08.html 2007-06.html 2008-04.html 2009-02.html 2009-12.html
2006-09.html 2007-07.html 2008-05.html 2009-03.html
2006-10.html 2007-08.html 2008-06.html 2009-04.html
$ |
一部、不要な月もありますが、データはないので気にする必要はありません。 次に、これらの HTML のパターンを解析して、ID を抽出します。
$ cat *.html | grep 'm: <a href="http://kazuomik.livejournal.com/' \
| sed -e 's/^.*livejournal\.com\///' -e 's/\.html\">.*$//' \
| sort -k1nr \
> id.txt
$ cat id.txt
341891
341649
341249
341145
340856
340482
340465
340137
339949
339476
...
2603
2409
2080
1960
1598
1332
1120
1008
722
495
$ wc -l id.txt
1335 id.txt
$ |
1,335 のエントリがありました。 あとは、各エントリのページをひとつずつ fetch します。
$ cat curl-all.sh
#!/bin/sh
for N in `cat id.txt`
do
curl http://kazuomik.livejournal.com/${N}.html -o ${N}.html
done
$ sh curl-all.sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 55323 100 55323 0 0 124k 0 --:--:-- --:--:-- --:--:-- 630k
...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 52824 100 52824 0 0 78390 0 --:--:-- --:--:-- --:--:-- 142k
$ |
25分程度で、1,335 すべてのエントリが fetch できました。 Tags: programming
|
 |
 |
 |
 |
|
 |
 |


 |
|
 |
 |
 |
 |
|
 |
 |
2009-05-28
長い間、このエントリをアップデートしてきましたが、ブログの移行に際して、今後はア ップデートはアップデートしないことにしました。 Tags: american_life, caltrain, computer_technology, español, français, game, health, immigration, internet, japanese, jobs_in_america, music, music_and_computer, music_gear, music_technology, programming, rebate, recycle_and_donation, second_life, tax, test, useful_link, walking
|
 |
 |
 |
 |
|
 |
 |



 |
|
 |
 |
 |
 |
|
 |
 |
Twitter でのつぶやき(update)を、 REST API Timeline Method を用いて、ひとつの XML ファイルにしましたが、ここでは、それを HTML に変換して、このブログに取り込みやすいようにします。本来ならば、JAXP などの XML ライブラリを用いるべきですが、ある事情で、最近は、シンプルな String クラスのみを用いて、parser をがりがり書くことが多いので、手っ取り早く、そちらで強引にやってしまいました。ま た、一部、手抜きをしているところもあります。 まずは、ひとつの status に対応するオブジェクトですが、とりあえず create_at (time) と text が最低限必要です。また、今後の拡張を考慮して、それに id (long) を加えておきました。
package net.kazmuzik.twitter;
import java.io.Serializable;
import java.util.Date;
public class TwitterStatus implements Serializable {
private Date time;
private long id;
private String text;
public TwitterStatus() {
}
public Date getTime() {
return time;
}
public long getId() {
return id;
}
public String getText() {
return text;
}
public void setTime(Date time) {
this.time = time;
}
public void setId(long id) {
this.id = id;
}
public void setText(String text) {
this.text = text;
}
} |
次は、XML ファイルを読み込んで、上記のオブジェクトを返す Reader (parser) です。
package net.kazmuzik.twitter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.Date;
public class TwitterXMLReader extends BufferedReader {
private static final boolean debug = false;
private static final String tag0 = "<created_at>";
private static final String tag1 = "<id>";
private static final String tag2 = "<text>";
private static final String tag3 = "</status>";
private static final int tag0len = tag0.length();
private static final int tag1len = tag1.length();
private static final int tag2len = tag2.length();
public TwitterXMLReader(Reader in) throws IOException {
super(in);
}
public TwitterXMLReader(InputStream in) throws IOException {
super(new InputStreamReader(in, "UTF-8"));
}
public TwitterStatus readStatus() throws IOException {
TwitterStatus status = new TwitterStatus();
int tag = 0;
while (true) {
String line = readLine();
if (line == null) {
return null;
}
if (debug) {
System.err.printf("%d: %s%n", tag, line.trim());
}
if (tag == 0) {
int n = line.indexOf(tag0);
if (n < 0) {
continue;
}
n += tag0len;
int m = line.indexOf('<', n);
if (m < 0) {
return null;
}
Date time = parseTime(line.substring(n,m));
status.setTime(time);
if (debug) {
System.err.printf("#: time=%TF %TT%n", time, time);
}
tag = 1;
continue;
}
else if (tag == 1) {
int n = line.indexOf(tag1);
if (n < 0) {
continue;
}
n += tag1len;
int m = line.indexOf('<', n);
if (m < 0) {
return null;
}
long id = Long.parseLong(line.substring(n,m));
status.setId(id);
if (debug) {
System.err.printf("#: id=%d%n", id);
}
tag = 2;
continue;
}
else if (tag == 2) {
int n = line.indexOf(tag2);
if (n < 0) {
continue;
}
n += tag2len;
int m = line.indexOf('<', n);
if (m < 0) {
return null;
}
String text = convertEntities(line.substring(n,m));
status.setText(text);
if (debug) {
System.err.printf("#: text=%s%n", text);
}
tag = 3;
continue;
}
else if (tag == 3) {
int n = line.indexOf(tag3);
if (n < 0) {
continue;
}
return status;
}
}
}
private static String convertEntities(String text) {
StringBuilder sb = new StringBuilder();
int n = 0;
int x = 0;
for (char c : text.toCharArray()) {
if (n == 0) {
if (c == '&') {
n = 1;
}
else {
sb.append(c);
}
continue;
}
else if (n == 1) {
if (c == '#') {
n = 2;
x = 0;
}
else {
sb.append('&');
sb.append(c);
n = 0;
}
continue;
}
else if (n == 2) {
if (c == ';') {
sb.append((char)x);
n = 0;
}
else if (c < '0' || c > '9') {
sb.append(c);
n = 0;
}
else {
x *= 10;
x += (c - '0');
}
continue;
}
}
return sb.toString();
}
private static Date parseTime(String s) {
return new Date(s);
}
} |
あとは、これを用いて、適当な HTML に変換してやります。
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Date;
import net.kazmuzik.twitter.TwitterStatus;
import net.kazmuzik.twitter.TwitterXMLReader;
public class TwitterXMLConverter {
public static void main(String[] args) throws Exception {
InputStream is = System.in;
if (args.length > 0) {
is = new FileInputStream(args[0]);
}
TwitterXMLReader in = new TwitterXMLReader(is);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out, "UTF-8"));
out.println("<html><head>");
out.println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />");
out.println("</head><body>");
out.println("<ul>");
Date prevTime = null;
while (true) {
TwitterStatus status = in.readStatus();
if (status == null) {
break;
}
Date time = status.getTime();
String text = addATag(status.getText());
if (prevTime != null) {
if (time.getDay() != prevTime.getDay()) {
out.println("</ul>");
out.println("<ul>");
}
}
out.printf("<li><i><font color=#0000cc>%TF %TT</font> "
+ "<a href=\"http://twitter.com/kazmuzik\">"
+ "<font color=#00cc00>#%d</font></a></i><br>",
time, time, status.getId());
out.printf("%s<br> </li>%n", text);
prevTime = time;
}
out.println("</ul>");
out.println("</body></html>");
out.flush();
out.close();
}
private static String addATag(String text) {
StringBuilder sb = new StringBuilder();
int n = 0;
while (true) {
int m = text.indexOf("http://", n);
if (m < 0) {
sb.append(text.substring(n));
break;
}
sb.append(text.substring(n,m));
n = text.indexOf(' ', m);
String url = null;
if (n < 0) {
url = text.substring(m);
}
else {
url = text.substring(m, n);
}
sb.append("<a href=\"");
sb.append(url);
sb.append("\">");
sb.append(url);
sb.append("</a>");
if (n < 0) {
break;
}
}
return sb.toString();
}
} |
これを実行して、HTML ファイルを作ります。
$ mkdir classes
$ javac -d classes *.java
$ java -classpath classes TwitterXMLConverter kazmuzik.xml > kazmuzik.html
$ |
これを、一日分ずつ、cut & paste で、ブログのエントリに貼付けていきました。 5/8/2009 のサンプルです。とりあえず、5月分だけ、作成しました。 せっかくなので、復習もかねて、JAXP でも使えば良かったかな、と反省しています。 2009-05-11 updateHeader に UTF-8 を指定しておきました。 Tags: programming
|
 |
 |
 |
 |
|
 |
 |


 |
|
 |
 |
 |
 |
|
 |
 |
4月は、このブログを更新する時間もありませんでしたが、その分、なるべく Twitter でつぶいていました。そこで、 Twitter API を用いて、なるべく簡単に このブログに取り込んでみることを考えてみました。 Twitter API は、HTTP ベースで、Search API と REST API があります。今回は、 REST API Timeline method の statuses/user_timeline を用います。HTTP ベースなので、curl コマンドで簡単にテストできます。
$ curl 'http://twitter.com/statuses/user_timeline.xml?screen_name=kazmuzik&count=200' > kazmuzik.xml
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 414k 100 414k 0 0 603k 0 --:--:-- --:--:-- --:--:-- 809k
$ cat kazmuzik.xml
<?xml version="1.0" encoding="UTF-8"?>
<statuses type="array">
<status>
<created_at>Sun May 10 15:38:12 +0000 2009</created_at>
<id>1755243926</id>
<text>140文字で表現できる内容です\
が、英語だと日本語の半分以\
下になってしまいます。ある\
程度、中身がある場合は、日\
本語が圧倒的に有利です。こ\
れも、Unicodeが普及してきたおか\
げです。</text>
<source>web</source>
<truncated>false</truncated>
<in_reply_to_status_id></in_reply_to_status_id>
<in_reply_to_user_id></in_reply_to_user_id>
<favorited>false</favorited>
<in_reply_to_screen_name></in_reply_to_screen_name>
<user>
<id>26517941</id>
<name>Kaz Muzik</name>
...
<statuses_count>204</statuses_count>
<notifications></notifications>
<following></following>
</user>
</status>
</statuses>
$ |
1回の API call で取得できる上限は 200個です。現在のところ、すでにその上限を超えているので、2ページ目も取得して、c oncatenate してから、つなぎの 3行をマニュアルで削除して、ひとつの XML ファイルにしました。
$ curl 'http://twitter.com/statuses/user_timeline.xml?screen_name=kazmuzik&count=200&page=2' >> kazmuzik.xml
$ vi kazmuzik.xml
$ |
これで、自分の今までのつぶやきがすべてひとつの XML ファイルに収まりました。ただし、上記の例のように、このままでは、扱いに不便なので、次 は、これを加工してみます。 Tags: internet, programming
|
 |
 |
 |
 |
|
 |
 |



 |
|
 |
 |
 |
 |
|
 |
 |
1/2/2009 には、Pro Tools LE 8 (など)の Plug-in のリストを載せましたが、各 .dpm ディレクトリの下には、Contents フォルダがあり、そこに Info.plist という XML ファイルがあります。そこで、このファイルを簡単に parse して、追加の情報も加えてみました。 本来ならば、DOM か SAX などの JAXP API を使えばいいのですが、通勤中の Caltrain の中でさっと開発したため、API ドキュメントにアクセスできず、強引に plain text として処理し、必要な項目だけを抜き出すことにしました。また、value も string のものだけをサポートしています。
$ cat PList.java
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
public class PList implements Serializable {
private Map<String,String> dict;
public PList() {
dict = new HashMap<String,String>();
}
public void put(String key, String value) {
dict.put(key, value);
}
public String get(String key) {
return dict.get(key);
}
public Map<String,String> getDict() {
return dict;
}
}
$ cat PListReader.java
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.PrintWriter;
public class PListReader extends BufferedReader {
public PListReader(Reader in) throws IOException {
super(in);
}
public PListReader(InputStream is) throws IOException {
this(new InputStreamReader(is, "UTF-8"));
}
public PListReader(String filename) throws IOException {
this(new FileInputStream(filename));
}
public String readKey() throws IOException {
while (true) {
String line = readLine();
if (line == null) {
return null;
}
int n = line.indexOf("<key>");
if (n < 0) {
continue;
}
int m = line.indexOf("</key>", n+5);
if (m < 0) {
continue;
}
return line.substring(n+5, m);
}
}
public String readStringValue() throws IOException {
String line = readLine();
if (line == null) {
return null;
}
int n = line.indexOf("<string>");
if (n < 0) {
return null;
}
int m = line.indexOf("</string>", n+8);
if (m < 0) {
return null;
}
return line.substring(n+8, m);
}
public String[] readKeyAndStringValue() throws IOException {
while (true) {
String key = readKey();
if (key == null) {
break;
}
String value = readStringValue();
if (value == null) {
continue;
}
return new String[] { key, value };
}
return null;
}
public PList readPList() throws IOException {
PList plist = new PList();
while (true) {
String[] pair = readKeyAndStringValue();
if (pair == null) {
break;
}
String key = pair[0];
String value = pair[1];
plist.put(key, value);
}
return plist;
}
public void printPList(PrintWriter out, String separator) throws IOException {
while (true) {
String[] pair = readKeyAndStringValue();
if (pair == null) {
break;
}
String key = pair[0];
String value = pair[1];
out.printf("%s%s%s%n", key, separator, value);
}
}
public static void main(String[] args) throws IOException {
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out, "UTF-8"));
if (args.length > 0) {
for (String filename : args) {
plist(out, filename);
}
}
else {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
while (true) {
String filename = in.readLine();
if (filename == null) {
break;
}
plist(out, filename);
}
}
out.flush();
out.close();
}
public static void plist(PrintWriter out, String filename) throws IOException {
out.printf("[ %s ]%n", filename);
PListReader in = new PListReader(filename);
in.printPList(out, " = ");
in.close();
out.println();
// out.flush();
}
}
$ cat DpmInfo.java
import java.io.File;
import java.io.IOException;
public class DpmInfo {
private static final String pluginFolderName
= "/Library/Application Support/Digidesign/Plug-ins";
private String folderName;
private String fileName;
private PList plist;
public DpmInfo(String dpmName) throws IOException {
folderName = dpmName;
if (! folderName.startsWith("/")) {
folderName = pluginFolderName + "/" + folderName;
}
if (! folderName.endsWith(".dpm")) {
folderName = folderName + ".dpm";
}
int n = folderName.lastIndexOf('/');
fileName = folderName.substring(n+1);
String plistFilename = folderName + "/Contents/Info.plist";
PListReader in = new PListReader(plistFilename);
plist = in.readPList();
in.close();
}
public String getFolderName() {
return folderName;
}
public String getFileName() {
return fileName;
}
public String getBundleName() {
return plist.get("CFBundleName");
}
public String getBundleVersion() {
return plist.get("CFBundleVersion");
}
public String getBundleInfo() {
String bundleInfo = plist.get("CFBundleGetInfoString");
if (bundleInfo == null) {
bundleInfo = "";
}
return bundleInfo;
}
}
$ cat DpmLister.java
import java.io.File;
import java.io.IOException;
public class DpmLister {
private static final int fontSize = 1;
private static final String pluginFolderName
= "/Library/Application Support/Digidesign/Plug-ins";
public static void main(String[] args) throws IOException {
File folder = new File(pluginFolderName);
System.out.println("<table border=1>");
System.out.print("<tr>");
System.out.print("<td align=center><i>File</i></td>");
System.out.print("<td align=center><i>Name</i></td>");
System.out.print("<td align=center><i>Version</i></td>");
System.out.print("<td align=center><i>Bundle Info</i></td>");
System.out.println("</tr>");
for (String dpmName : folder.list()) {
if (! dpmName.endsWith(".dpm")) {
continue;
}
DpmInfo dpmInfo = new DpmInfo(dpmName);
printDpmInfo(dpmInfo);
}
System.out.println("</table>");
System.out.flush();
}
public static void printDpmInfo(DpmInfo dpmInfo) throws IOException {
String fileName = dpmInfo.getFileName();
String bundleName = dpmInfo.getBundleName();
String bundleVersion = dpmInfo.getBundleVersion();
String bundleInfo = dpmInfo.getBundleInfo();
if (bundleInfo == null) {
bundleInfo = "";
}
print(new String[] { fileName, bundleName, bundleVersion, bundleInfo });
}
private static void print(String[] ss) {
System.out.print("<tr>");
for (String s : ss) {
if (s == null || s.length() == 0) {
s = "∓nbsp;";
}
System.out.printf("<td align=left valign=top><font size=%d>%s</font></td>", fontSize, s);
}
System.out.println("</tr>");
}
}
$ javac *.java
$ java DpmLister > dpmlist.html
$ |
File | Name | Version | Bundle Info |
AIRChorus.dpm | AIRChorus | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRDistortion.dpm | AIRDistortion | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRDynamicDelay.dpm | AIRDynamicDelay | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIREnhancer.dpm | AIREnhancer | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIREnsemble.dpm | AIREnsemble | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRFilterGate.dpm | AIRFilterGate | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRFlanger.dpm | AIRFlanger | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRFrequencyShifter.dpm | AIRFrequencyShifter | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRFuzz-Wah.dpm | AIRFuzz-Wah | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRKillEQ.dpm | AIRKillEQ | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRLo-Fi.dpm | AIRLo-Fi | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRMulti-Chorus.dpm | AIRMulti-Chorus | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRMulti-Delay.dpm | AIRMulti-Delay | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRNon-linearReverb.dpm | AIRNon-LinearReverb | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRPhaser.dpm | AIRPhaser | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRReverb.dpm | AIRReverb | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRSpringReverb.dpm | AIRSpringReverb | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRStereoWidth.dpm | AIRStereoWidth | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRTalkbox.dpm | AIRTalkbox | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
AIRVintageFilter.dpm | AIRVintageFilter | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
Analog_Channel_LE.dpm | Analog_Channel_LE | 3.2x18 | 3.2x18, Copyright 1998-2007 McDowell Signal Processing, LLC |
BF Essential Clip Remover.dpm | BF Essential Clip Remover | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
BF Essential Corr.dpm | BF Essential Corr | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
BF Essential Meter.dpm | BF Essential Meter | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
BF Essential Noise.dpm | BF Essential Noise | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
bombfactory BF-2A.dpm | bombfactory BF-2A | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
bombfactory BF-3A.dpm | bombfactory BF-3A | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
bombfactory BF76.dpm | bombfactory BF76 | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Boom.dpm | Boom | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
Chorus.dpm | Chorus | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Chrome_Tone_LE.dpm | Chrome_Tone_LE | 2.2x18 | 2.2x18, Copyright 1998-2007 McDowell Signal Processing, LLC |
Click.dpm | Click | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
CompressorBank_LE.dpm | CompressorBank_LE | 4.2x18 | 4.2x18, Copyright 1998-2007 McDowell Signal Processing, LLC |
Cosmonaut Voice.dpm | Cosmonaut Voice | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
D-Verb.dpm | D-Verb | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
DB-33.dpm | DB-33 | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
DigiReWire.dpm | DigiReWire | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Dither.dpm | Dither | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Dynamics III.dpm | Dynamics III | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Elastic Audio.dpm | Elastic Audio | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Eleven Free.dpm | Eleven Free | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Eleven LE.dpm | Eleven LE | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
EQ III.dpm | EQ III | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
EZplayer.dpm | EZplayer | 7.3d0 | ? Toontrack AB 2006, Version 1.0.2 |
Fairchild 660.dpm | Fairchild 660 | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Fairchild 670.dpm | Fairchild 670 | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
FilterBank_LE.dpm | FilterBank_LE | 4.2x18 | 4.2x18, Copyright 1998-2007 McDowell Signal Processing, LLC |
Flanger.dpm | Flanger | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Hybrid.dpm | Hybrid | 1.5.2.7597 | 1.5.2.7597 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
Invert-Duplicate.dpm | Invert-Duplicate | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
JOEMEEK Compressor.dpm | JOEMEEK Compressor | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
JOEMEEK Meequalizer.dpm | JOEMEEK Meequalizer | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
LoFi.dpm | LoFi | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Maxim.dpm | Maxim | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
MelodyneBridge.dpm | | 3.2.2.2 | |
MiniGrand.dpm | MiniGrand | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
ML4000_LE.dpm | ML4000_LE | 1.1x18 | 1.1x18, Copyright 1998-2007 McDowell Signal Processing, LLC |
Mod Delay II.dpm | Mod Delay II | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
moogerfooger AD.dpm | moogerfooger AD | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
moogerfooger LP.dpm | moogerfooger LP | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
moogerfooger Ph.dpm | moogerfooger Ph | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
moogerfooger RM.dpm | moogerfooger RM | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Multi-Tap Delay.dpm | Multi-Tap Delay | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Normalize-Gain.dpm | Normalize-Gain | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Ping-Pong Delay.dpm | Ping-Pong Delay | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Purple Audio MC77.dpm | Purple Audio MC77 | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
RectiFi.dpm | RectiFi | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Reverse-DC Removal.dpm | Reverse-DC Removal | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Revolver_LE.dpm | Revolver_LE | 1.2x18 | 1.2x18, Copyright 1998-2007 McDowell Signal Processing, LLC |
SansAmp PSA-1.dpm | SansAmp PSA-1 | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
SciFi.dpm | SciFi | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Signal Generator.dpm | Signal Generator | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
SignalTools.dpm | SignalTools | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Smack! LE.dpm | Smack! LE | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
SoundReplacer.dpm | SoundReplacer | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Structure.dpm | Structure LE | 1.0.2.7584 | 1.0.2.7584 Copyright 2008 Digidesign, A Division of Avid Technology, Inc. |
Superior Drummer.dpm | Superior Drummer | 7.3d0 | ? Toontrack AB 2007, Version 2.0.1 |
Synth_One_LE.dpm | Synth_One_LE | 4.2x18 | 4.2x18, Copyright 1998-2007 McDowell Signal Processing, LLC |
Tel-Ray Delay.dpm | Tel-Ray Delay | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Time Comp-Exp-Pitch Shift.dpm | Time Comp-Exp-Pitch Shift | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Time Shift.dpm | Time Shift | 8.0.0f314 | 8.0.0, Copyright ? 2005 by Digidesign, a division of Avid. All rights reserved. |
TimeAdjuster.dpm | TimeAdjuster | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
TL AutoPan.dpm | TL AutoPan | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
TL EveryPhase.dpm | TL EveryPhase | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
TL InTune.dpm | TL InTune | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
TL MasterMeter.dpm | TL MasterMeter | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
TL Metro.dpm | TL Metro | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
TL Space Native.dpm | TL Space Native | 8.0.0f314 | 8.0.0, Copyright 1991-2006 Digidesign, A Division of Avid Technology, Inc. |
Trim.dpm | Trim | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Vacuum.dpm | Vacuum | 1.0.0.8542 | 1.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
VariFi.dpm | VariFi | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Voce Chorus-Vibrato.dpm | Voce Chorus-Vibrato | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
Voce Spin.dpm | Voce Spin | 8.0.0f314 | 8.0.0, Copyright 1991-2008 Digidesign, A Division of Avid Technology, Inc. |
WaveShell-DAE 6.0.6.dpm | WaveShell-DAE 6.0.6 | 6.0.6 | |
XPand!.dpm | Xpand! | 2.0.0.8542 | 2.0.0.8542 Copyright 2005-2007 Digidesign, A Division of Avid Technology, Inc. |
Tags: music_technology, programming
|
 |
 |
 |
 |
|
 |
 |


 |
|
 |
 |
 |
 |
|
 |
 |
正八面体は、思った以上に簡単だったので、一辺が 2倍の 17.32m のピラミッドを作ってみます。まず、 ひとつの prim で作成できる最大の一辺 8.66m の正三角形を、4つ組み合わせて、一辺 17.32m の正三角形を作成します。
setRotation() {
llSetRot(llEuler2Rot(<0.0, 0.0, PI>));
}
rezTriangles() {
vector p = llGetPos();
llRezAtRoot("triangle", p + < 5.0, 0.0, 0.0>, <0.0, 0.0, 0.0>, ZERO_ROTATION, 0);
llRezAtRoot("triangle", p + <-2.5, 4.330127, 0.0>, <0.0, 0.0, 0.0>, ZERO_ROTATION, 0);
llRezAtRoot("triangle", p + <-2.5,-4.330127, 0.0>, <0.0, 0.0, 0.0>, ZERO_ROTATION, 0);
}
default {
state_entry() {
}
touch_start(integer total_number) {
llRequestPermissions(llGetOwner(), PERMISSION_CHANGE_LINKS);
}
run_time_permissions(integer perm) {
if (perm & PERMISSION_CHANGE_LINKS) {
setRotation();
rezTriangles();
}
}
object_rez(key id) {
llCreateLink(id, TRUE);
}
} |
一辺 8.66m の正三角形の prim に、このスクリプトと、同じ prim を "triangle" という名前で、contents に入れます。これを touch すると、大きな正三角形が出来ます。まずは、自分自身を 180°回転してから、それぞれの辺の方向 5m のところに、つまり、辺に対して線対称となるように、同じ正三角形を 3個、配置します。この大きな三角形を "large triangle" としておきます。 この "large triangle" と、8.66m の正方形の prim "square 8.66m" を、底辺の中心となる prim に入れて、次のスクリプトを実行して、touch すると、大きなピラミッドができます。
rezTriangle(vector pos, vector rot) {
llRezAtRoot("large triangle", pos, <0.0, 0.0, 0.0>, llEuler2Rot(rot), 0);
}
rezTriangles() {
vector p = llGetPos();
rezTriangle(p + <-5.773502, 0.0, 4.08248>, <0.0, PI-0.95532, 0.0>);
rezTriangle(p + < 5.773502, 0.0, 4.08248>, <0.0, 0.95532, 0.0>);
rezTriangle(p + <0.0,-5.773502, 4.08248>, <PI+0.95532, 0.0, PI_BY_TWO>);
rezTriangle(p + <0.0, 5.773502, 4.08248>, <PI-0.95532, 0.0,-PI_BY_TWO>);
}
rezSquares() {
rezSquaresX(llGetPos());
}
rezSquaresX(vector pos) {
rezSquaresY(pos + <-4.330127, 0.0, 0.0>);
rezSquaresY(pos + < 4.330127, 0.0, 0.0>);
}
rezSquaresY(vector pos) {
rezSquare(pos + <0.0, -4.330127, 0.0>);
rezSquare(pos + <0.0, 4.330127, 0.0>);
}
rezSquare(vector pos) {
llRezObject("square 8.66m", pos, <0.0, 0.0, 0.0>, ZERO_ROTATION, 0);
}
setInvisible() {
llSetScale(<0.01, 0.01, 0.01>);
llSetAlpha(0.0, ALL_SIDES);
}
default {
state_entry() {
}
touch_start(integer total_number) {
llRequestPermissions(llGetOwner(), PERMISSION_CHANGE_LINKS);
}
run_time_permissions(integer perm) {
if (perm & PERMISSION_CHANGE_LINKS) {
rezTriangles();
rezSquares();
setInvisible();
}
}
object_rez(key id) {
llCreateLink(id, TRUE);
}
} |
側面の大きな正三角形を作成したときに、root となる prim を 180°回転したせいか、rotation の vector は、調整する必要がありました。 Tags: programming, second_life
|
 |
 |
 |
 |
|
 |
 |

 |
|
 |
 |
 |
 |
|
 |
 |
12/5 には、pyramid を作成しましたが、そのスクリプトを応用して、 正八面体(Regular Octahedron)を作ってみました。前回の pyramid は、すべての辺の長さが等しいので、四角錐の 4つの正三角形の側面を、下の方にも作り、底面の正方形を消すだけです。
rezTriangle(vector pos, vector rot) {
llRezAtRoot("triangle", pos, <0.0, 0.0, 0.0>, llEuler2Rot(rot), 0);
}
rezTriangles() {
vector p = llGetPos();
rezTriangle(p + <-2.88675, 0.0, 2.04124>, <0.0, -0.95532, 0.0>);
rezTriangle(p + < 2.88675, 0.0, 2.04124>, <0.0, PI+0.95532, 0.0>);
rezTriangle(p + <0.0,-2.88675, 2.04124>, < 0.95532, 0.0, PI_BY_TWO>);
rezTriangle(p + <0.0, 2.88675, 2.04124>, <-0.95532, 0.0, -PI_BY_TWO>);
rezTriangle(p + <-2.88675, 0.0, -2.04124>, <0.0, 0.95532, 0.0>);
rezTriangle(p + < 2.88675, 0.0, -2.04124>, <0.0, PI-0.95532, 0.0>);
rezTriangle(p + <0.0,-2.88675, -2.04124>, <-0.95532, 0.0, PI_BY_TWO>);
rezTriangle(p + <0.0, 2.88675, -2.04124>, < 0.95532, 0.0, -PI_BY_TWO>);
}
setInvisible() {
llSetScale(<0.01, 0.01, 0.01>);
llSetAlpha(0.0, ALL_SIDES);
}
default {
state_entry() {
}
touch_start(integer total_number) {
llRequestPermissions(llGetOwner(), PERMISSION_CHANGE_LINKS);
}
run_time_permissions(integer perm) {
if (perm & PERMISSION_CHANGE_LINKS) {
rezTriangles();
setInvisible();
}
}
object_rez(key id) {
llCreateLink(id, TRUE);
}
} |
Tags: programming, second_life
|
 |
 |
 |
 |
|
 |
 |


 |
|
 |
 |
 |
 |
|
 |
 |
20m の大きな Cube (立方体)の作成に成功したので、今回は Pyramid にチャレンジします。まずは、各面がひとつの prim のものから始めます。 Prim の形状(building block type)には、今まで使用してきた Box の他にも、Cylinder (円柱), Sphere (球), Torus (ドーナツ形)などがあります。今回は、正三角形の面があるので、Prism (三角錐)を使ってみます。これで、X, Y軸方向の長さを 10m にセットしたところ、大きな正三角形がでてきました。しかし、一辺 10m の正方形よりは、ひとまわり小さく、一辺が 10m はないようです。そこで、タイルの texture を貼付けてみたところ、高さが 7.5m で、中心は、1/3 の、底辺から 2.5m のところにあることがわかりました。ちなみに、高さの方向は、X軸で、頂点が (5.0, 0), 底辺が x=-2.5 です。このため、底面の正方形の一辺の長さは、7.5 * 2 / sqrt(3) = 5 * sqrt(3) = 8.66025m となります。つまり、すべての辺が 8.66m の正四角錐を作ることになります。 まずは、一辺 8.66025m の正方形の prim を作成して、その中に、上記の正三角形の prim を入れます。あとは、この正三角形を 4回、適当に回転して、適切な位置に rez して link するスクリプトを入れて、実行するだけです。しかし、その position と rotation を求めるのが、簡単ではありません。まずは、スクリプトから、紹介します。
rezTriangles() {
vector p = llGetPos();
llRezAtRoot("triangle", p + <-2.88675, 0.0, 2.04124>, <0.0, 0.0, 0.0>, llEuler2Rot(<0.0, -0.95532, 0.0>), 0);
llRezAtRoot("triangle", p + < 2.88675, 0.0, 2.04124>, <0.0, 0.0, 0.0>, llEuler2Rot(<0.0, PI+0.95532, 0.0>), 0);
llRezAtRoot("triangle", p + <0.0,-2.88675, 2.04124>, <0.0, 0.0, 0.0>, llEuler2Rot(< 0.95532, 0.0, PI_BY_TWO>), 0);
llRezAtRoot("triangle", p + <0.0, 2.88675, 2.04124>, <0.0, 0.0, 0.0>, llEuler2Rot(<-0.95532, 0.0, -PI_BY_TWO>), 0);
}
default {
state_entry() {
}
touch_start(integer total_number) {
llRequestPermissions(llGetOwner(), PERMISSION_CHANGE_LINKS);
}
run_time_permissions(integer perm) {
if (perm & PERMISSION_CHANGE_LINKS) {
rezTriangles();
}
}
object_rez(key id) {
llCreateLink(id, TRUE);
}
} |
まず、最初の面ですが、X軸とZ軸を含む平面で考えると、正三角錐の高さの平方は、(7.5) ^2 - (5 * sqrt(3) / 2)^2 = (5/2)^2 * 6 なので、高さは、(5/2)*sqrt(6) = 6.12372m となります。これと、中心が底辺から 1/3 のところにあることを利用して、上記スクリプトでの position が決まります。 また、rotation については、Y軸の上(北)から見て、負の方向に回転する必要があります。ここでは、p ython を利用してみました。
$ python
Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26)
>>> from math import sqrt
>>> from math import atan2
>>> 5*sqrt(3)
8.6602540378443855
>>> 5*sqrt(6)/2
6.1237243569579451
>>> atan2( sqrt(6), sqrt(3) )
0.9553166181245093
>>>
|
ひとつ決まれば、あとの 3つは、符号を変えたり、軸を変えたり、rotation に関しては、PI (180度)や PI_BY_TWO (90度) だけ調整することにより、試行錯誤でも得られます。   Tags: programming, second_life
|
 |
 |
 |
 |
|
 |
 |


 |
|
 |
 |
 |
 |
|
 |
 |
20m cube の応用として、上空に、個人専用の Fitting Room を作成してみます。 Prim を作成して、20m cube のオブジェクトと、次のスクリプトを入れます。
float height = 3776.0;
moveUp() {
vector p = llGetPos();
float h = p.z;
while (h + 10.0 < height) {
p += <0.0, 0.0, 10.0>;
h += 10.0;
llSetPos(p);
}
p.z = height;
llSetPos(p);
}
default {
state_entry() {
}
changed(integer param) {
if (param & CHANGED_LINK) {
moveUp();
string name = llGetInventoryName(INVENTORY_OBJECT, 0);
llRezObject(name, llGetPos(), <0.0, 0.0, 0.0>, ZERO_ROTATION, 0);
llSetTimerEvent(6.0);
}
}
timer() {
llDie();
}
} |
これにすわると、1行目に指定された高さまで移動して、そこで、20m cube を作成して、timer() イベントにより、自分自身を消します。これで、上空の 20m cube の中に、閉じ込められることになります。 Second Life 内に、自分の家がない場合、いろいろな服を買ったり、free で get してきても、自由に試すことが、なかなか出来ないかもしれません。しかし、このスクリ プトが入れた prim があれば、sandbox へ行って、rez して、座るだけで、20m cube の自分専用の fitting room となります。 Sandbox では、使用後は、削除していくのがエチケットですが、この場合、上空から、自分自身(a vator) が落下してしまうことになります。 Tags: programming, second_life
|
 |
 |
 |
 |
|
 |
 |


 |
|
 |
 |
 |
 |
|
 |
 |
前回の続きで、20m cube を構成する 8つの parts を、link して、ひとつのオブジェクトとします。 まずは、8つのオブジェクトに、"cube 10m ---", "cube 10m ---+", ..., "cube 10m +++" と名付けて、take します。符号は、順に、X, Y, Z軸の、どちらの surface をもつかを示します。例えば、"---" は、西、南、下の 3つの面をもつことをあらわします。 次は、上記のオブジェクトを rez して link するスクリプトです。
rezCube(string object, vector pos) {
llRezObject(object, pos, <0.0, 0.0, 0.0>, ZERO_ROTATION, 0);
}
rezCubes() {
string name = "cube 10m ";
vector pos = llGetPos();
rezCubesX(name, pos);
}
rezCubesX(string name, vector pos) {
rezCubesY(name + "-", pos + <-5.0, 0.0, 0.0>);
rezCubesY(name + "+", pos + < 5.0, 0.0, 0.0>);
}
rezCubesY(string name, vector pos) {
rezCubesZ(name + "-", pos + <0.0, -5.0, 0.0>);
rezCubesZ(name + "+", pos + <0.0, 5.0, 0.0>);
}
rezCubesZ(string name, vector pos) {
rezCube(name + "-", pos + <0.0, 0.0, -5.0>);
rezCube(name + "+", pos + <0.0, 0.0, 5.0>);
}
setInvisible() {
llSetScale(<0.01, 0.01, 0.01>);
llSetAlpha(0.0, ALL_SIDES);
}
default {
state_entry() {
}
touch_start(integer n) {
key owner = llGetOwner();
integer i;
for (i = 0; i < n; i++) {
if (llDetectedKey(i) == owner) {
llRequestPermissions(owner, PERMISSION_CHANGE_LINKS);
}
}
}
run_time_permissions(integer perm) {
if (perm & PERMISSION_CHANGE_LINKS) {
rezCubes();
setInvisible();
}
}
object_rez(key id) {
llCreateLink(id, TRUE);
}
} |
このスクリプトと上記の 8つのオブジェクトを入れた prim を touch することにより、一辺 20m の cube が、ひとつのオブジェクトとして、作成できます。いったん、link されてしまえば、contents の内容は、すべて削除してもかまいません。これで、例えば、object の編集で、texture を一気に変更すること、などができるようになります。もちろん、rez や take も、1回の操作で、できます。 その後、30m cube の作成にもチャレンジしてみましたが、llRezObject() の制限にひっかかってきました。 11/30 には、各軸で、20m が制限らしいと書きましたが、今日の結果では、root position の直線距離で、17m が限界のようです。例えば、一辺 10m の立方体を 2つ並べることを考えます。ひとつの面を共有するように並べた場合、中心間の距離は、1 0m で、これは大丈夫です。また、ひとつの辺を共有するように並べた場合は、10 x sqrt(2) = 14.14213m で、これも大丈夫です。ところが、ひとつの頂点だけを共有するように、X,Y,Z各軸 に 10m ずつ平行移動するような場合は、10 x sqrt(3) = 17.32050m となり、17m を超えているせいか、rez に失敗してしまいます。 Tags: programming, second_life
|
 |
 |
 |
 |
|
 |
 |

 |
|
 |
 |
 |
 |
|
 |
 |
Flexible に cuboid の surface を作れる script を書いたので、これを利用して、一辺 20m の Cube (立方体)を作ってみます。 まず、surface 用のスクリプトでは、size = <10.0, 10.0, 10.0> としておきます。 次に、20m cube を、8つの 10m cube に分解して、それぞれの cube の 3つの surface を作るスクリプトです。
vector size = <10.0, 10.0, 10.0>;
integer rezParam;
rezRectangle(string surface, vector pos, integer param) {
llRezAtRoot(surface, pos, <0.0, 0.0, 0.0>, ZERO_ROTATION, param);
}
rezRectangles() {
string surface = llGetInventoryName(INVENTORY_OBJECT, 0);
vector pos = llGetPos();
if (rezParam & 1) {
rezRectangle(surface, pos + <-size.x/2, 0.0, 0.0>, 1);
}
if (rezParam & 2) {
rezRectangle(surface, pos + < size.x/2, 0.0, 0.0>, 1);
}
if (rezParam & 4) {
rezRectangle(surface, pos + < 0.0,-size.y/2, 0.0>, 2);
}
if (rezParam & 8) {
rezRectangle(surface, pos + < 0.0, size.y/2, 0.0>, 2);
}
if (rezParam & 16) {
rezRectangle(surface, pos + < 0.0, 0.0,-size.z/2>, 3);
}
if (rezParam & 32) {
rezRectangle(surface, pos + < 0.0, 0.0, size.z/2>, 3);
}
}
setInvisible() {
llSetScale(<0.01, 0.01, 0.01>);
llSetAlpha(0.0, ALL_SIDES);
}
default {
state_entry() {
}
touch_start(integer n) {
if (rezParam > 0) {
llRequestPermissions(llGetOwner(), PERMISSION_CHANGE_LINKS);
}
}
on_rez(integer param) {
rezParam = param;
}
run_time_permissions(integer perm) {
if (perm & PERMISSION_CHANGE_LINKS) {
rezRectangles();
setInvisible();
}
}
object_rez(key id) {
llCreateLink(id, TRUE);
}
} |
これは、次のスクリプトを含むオブジェクトから、rez されますが、そのときのパラメータから、どの surface をつくるか決定します。例えば、21 = 1 + 4 + 16 の場合、1 により、X軸(東西)の西側の面を作成します。同様に、4 は Y軸(南北)の南側の面、... となります。 Rez のときには、パラメータを保存するだけで、実際には touch されてから、surface(s) を rez して、link します。これは、全体では 24 = 3 x 8 = 4 x 6 個の 10m x 10m surface になり、llCreateLink() は 1秒間 sleep するため、一気にすべて rez してしまうと、event queue が overflow してしまうためです。これは、複数のオブジェクトを link するときの重要な注意点で、できるだけ、使用時ではなく、事前にlink しておくことが大切です。このため、スクリプトを作成時用と使用時用の 2つを準備することになり、少し煩雑になってしまいます。 次に、上記のスクリプトを含む 8つのオブジェクトを生成するスクリプトです。
rezCube(string object, vector pos, integer param) {
llRezObject(object, pos, <0.0, 0.0, 0.0>, ZERO_ROTATION, param);
}
rezCubes() {
string object = llGetInventoryName(INVENTORY_OBJECT, 0);
vector pos = llGetPos();
rezCubesX(object, pos, 0);
}
rezCubesX(string object, vector pos, integer param) {
rezCubesY(object, pos + <-5.0, 0.0, 0.0>, param+1);
rezCubesY(object, pos + < 5.0, 0.0, 0.0>, param+2);
}
rezCubesY(string object, vector pos, integer param) {
rezCubesZ(object, pos + <0.0, -5.0, 0.0>, param+4);
rezCubesZ(object, pos + <0.0, 5.0, 0.0>, param+8);
}
rezCubesZ(string object, vector pos, integer param) {
rezCube(object, pos + <0.0, 0.0, -5.0>, param+16);
rezCube(object, pos + <0.0, 0.0, 5.0>, param+32);
}
default {
state_entry() {
}
touch_start(integer n) {
key owner = llGetOwner();
integer i;
for (i = 0; i < n; i++) {
if (llDetectedKey(i) == owner) {
rezCubes();
}
}
}
} |
このスクリプトと、上記のスクリプトを含むオブジェクトをもつ prim を作成して、touch すると、それを中心に、立体的に 8つの prim が配置されるので、それぞれを順番に touch していくことにより、20m cube が作成されます。ただし、この時点では、8つの parts は link されていません。また、touch するときは、event queue が overflow しないように、あまり急ぎすぎては、いけません。 つづくTags: programming, second_life
|
 |
 |
 |
 |
|
 |
 |


 |
|
 |
 |
 |
 |
|
 |
 |
先週は、大きな square (正方形)を作りましたが、今週は、平面から、立体に challenge を移しました。このために、Z軸も考慮する必要があるため、できるだけ、X, Y, Z 軸に対して、対称的に扱えるようにしました。 まずは、直方体 (cuboid) の面 (surface) を作るためのスクリプトです。簡単のため、各辺の長さは、1行目に vector として記述してあります。この prim を llRezObject() で rez すると、最後のパラメータが on_rez() イベントのパラメータとして渡ってくるので、これで、どの面を作成するのかを決定しま す。これが、1 の場合は、X軸に垂直な面を作るため、この例では、4m x 5m の長方形になります。2, 3 の場合は、同様に、Y軸、Z軸に垂直な長方形を作成します。また、普通に、inven tory から、drag and drop すると、パラメータが 0 となるため、特に、大きさは変更されず、このため、オブジェクトの編集やデバッグも容 易に行えます。
vector size = <3.0, 4.0, 5.0>;
setSize(integer param) {
vector v = size;
if (param == 1) {
v.x = 0.01;
}
else if (param == 2) {
v.y = 0.01;
}
else if (param == 3) {
v.z = 0.01;
}
else {
return;
}
llSetScale(v);
}
default {
state_entry() {
}
on_rez(integer param) {
if (param > 0) {
setSize(param);
}
}
} |
次に、これを利用して、cuboid の 6つの面を作成して、link するスクリプトです。中心になる prim にこのスクリプトと、上記のスクリプトを含む prim "rectangle surface" を入れて、touch すると、6つの面を作成して、link して、自分自身(中心の prim)は、可能な限り小さくなって、見えなくなります。
vector size = <3.0, 4.0, 5.0>;
key owner;
rezRectangle(vector pos, integer param) {
llRezAtRoot("rectangle surface", pos, <0.0, 0.0, 0.0>, ZERO_ROTATION, param);
}
rezRectangles() {
vector pos = llGetPos();
rezRectangle(pos + < size.x/2, 0.0, 0.0>, 1);
rezRectangle(pos + <-size.x/2, 0.0, 0.0>, 1);
rezRectangle(pos + < 0.0, size.y/2, 0.0>, 2);
rezRectangle(pos + < 0.0,-size.y/2, 0.0>, 2);
rezRectangle(pos + < 0.0, 0.0, size.z/2>, 3);
rezRectangle(pos + < 0.0, 0.0,-size.z/2>, 3);
}
setInvisible() {
llSetScale(<0.01, 0.01, 0.01>);
llSetAlpha(0.0, ALL_SIDES);
}
default {
state_entry() {
owner = llGetOwner();
}
touch_start(integer n) {
llRequestPermissions(owner, PERMISSION_CHANGE_LINKS);
}
run_time_permissions(integer perm) {
if (perm & PERMISSION_CHANGE_LINKS) {
rezRectangles();
setInvisible();
}
}
object_rez(key id) {
llCreateLink(id, TRUE);
}
} |
これで、X軸方向に 3m, Y軸方向に 4m, Z軸方向に 5m の直方体(の6面)が作成され、中心の小さな見えない prim に link されます。 1行目の vector の値を変更することにより、各辺を 10m までの範囲で、変更することができます。 Tags: programming, second_life
|
 |
 |
 |
 |
|
 |
 |

 |
|
 |
 |
 |
 |
|
 |
 |
Face Light を自作してみました。 昨日の snapshot(s) などを見ると、顔が暗くなっています。妻のアドバイスによると、face light というアイテムがあり、それを装備することにより、顔が明るくなって、美しく見えると のことです。といっても、free の face light を探すのも面倒なので、自分でスクリプトを書いて、実装することにしました。 基本的なアイデアは、prim をひとつ(あるいは複数)、顔の正面に置いて、 Lightの設定により、光源として使うことです。ただし、光源の prim が見えてしまっては邪魔なので、見えないようにする工夫が必要です。また、最初から、見 えないような prim を作ってしまうと、編集できなくなってしまうので、スクリプト内の on_rez() イベントで、見えなくすることにします。 まずは、光源の prim を作成します。Features タブに、Light の項目があるので、check して、必要ならばパラメータを調整します。それから、Contents に、次の、見えなくするスクリプトを入れます。基本的には、llSetAlpha() で 0.0 を設定することにより、透明にしていますが、念のため、サイズをできるだけ小さくして います。
setInvisible() {
llSetScale(<0.01, 0.01, 0.01>);
llSetAlpha(0.0, ALL_SIDES);
}
default {
state_entry() {
}
on_rez(integer param) {
setInvisible();
}
} | |
これに、"light" と名付けて、take します。 次に、Nose (など)に attach (装着)する prim を作成し、上記の "light" object を入れます。さらに次のスクリプトにより、touch_start() イベントを受け取ったら、"light" object を rez して、link することにします。
string light = "light";
key owner;
setLightName() {
if (llGetInventoryNumber(INVENTORY_OBJECT) > 0) {
light = llGetInventoryName(INVENTORY_OBJECT, 0);
}
}
rezLight(vector pos) {
llRezObject(light, pos, <0.0, 0.0, 0.0>, ZERO_ROTATION, 0);
}
rezLights() {
setLightName();
vector pos = llGetPos();
vector v = <0.10, 0.0, 0.0>;
vector p = pos + v;
rezLight(p);
}
default {
state_entry() {
owner = llGetOwner();
}
touch_start(integer n) {
integer i;
for (i = 0; i < n; i++) {
if (llDetectedKey(i) == owner) {
llRequestPermissions(owner, PERMISSION_CHANGE_LINKS);
}
}
}
run_time_permissions(integer perm) {
if (perm & PERMISSION_CHANGE_LINKS) {
rezLights();
}
}
object_rez(key id) {
llCreateLink(id, TRUE);
}
} | |
これで、touch すると、このオブジェクトには、見えない光源となるオブジェクトが link されることになります。 なお、この例では、attach される部所の 10cm のところに、光源のオブジェクトを 1個だけ、配置しています。必要ならば、光源の個数や場所を調整しておきます。 この時点で、Contents の中身は不要になるので、いったん削除しておきます。 さらに、attach() イベントを受け取ったら、自分自身を同様に見えなくする最初のものと似たスクリプトを 入れます。
setInvisible() {
llSetScale(<0.01, 0.01, 0.01>);
llSetAlpha(0.0, ALL_SIDES);
}
default {
state_entry() {
}
attach(key id) {
setInvisible();
}
} | |
これを take して、自分の inventory に入れておきます。このオブジェクトを、例えば nose に attach すると、鼻の 10cm 先に、光源ができて、顔が明るくなるわけです。 上記のスクリプトや、object のパラメータを変更することにより、光源の数、距離、色などを調整することが可能です。た だし、あまり多くの光源を使うと、逆に陰ができたりして、調整がむずかしくなることが あるので、注意が必要です。 下記は、snapshots ですが、以前の snapshot と比べて、顔の色が明るくなっているのが、わかります。特に、左の snapshot は、夜ですが、明るく照らされているのがわかります。 Tags: programming, second_life
|
 |
 |
 |
 |
|
 |
 |


 |
|
 |
 |
 |
 |
|
 |
 |
11/28 には、object の rez や link には、10m の壁があるようだと書きましたが、いろいろ試してみたところ、どうも、それぞれの軸に対して 20m が限界のようです。ただし、llRezAtRoot() では、object の原点で決まるのに対して、link では、object の中心で決まるようです。Spec を調べたわけではなく、自分でいくつかスクリプトを書いて確かめてみただけなので、ひ ょっとして間違いがあるかもしれませんが。(*) このため、正方形の大きな object を作成しようとした時には、今まで紹介したように、 ひとつの object としては、30m まで、また、 ひとつの script から複数の object を rez する場合には 50m というのが、限界のようです。ただし、後者に対しては、複数の入れ子になった object を用意して、 on_rez() イベントで、連鎖的に行う場合には、もっと大きなものが作れると思います。 なお、 11/29 のタイルの 50m square floor は、厚さを 1m で作成しましたが、smoke texture に変更して、厚さも 0.01m に変更しようとしたところ、texture はすべてに適用されましたが、size (scale) は、root object にだけ適用されました。このため、表面がでこぼこになってしまったため、作り直しまし た。  まずは、右上に配置する 30m(東西, X軸) x 20m(南北, Y軸)の長方形の object を作成します。このために、まず、prim をひとつ作成して、size を 10m x 10m x 0.01m にし、Smoke Texture を貼付けます。これを、"square 10m" と名付けて、いったん inventory に取り込みます。これを、再び rez して、この中に、同じ "square 10m" を入れ、次のようなスクリプトを新規作成します。
string square10 = "square 10m";
key owner;
rezObjects() {
vector pos = llGetPos();
integer i;
for (i = -1; i < 2; i++) {
integer j;
for (j = 0; j < 2; j++) {
if (i != 0 || j != 0) {
llRezObject(square10, pos + <10.0 * (float)i, 10.0 * (float)j, 0.0>,
<0.0, 0.0, 0.0>, <0.0, 0.0, 0,0>, 0);
}
}
}
}
default {
state_entry() {
owner = llGetOwner();
}
touch_start(integer total_number) {
integer i;
for (i = 0; i < total_number; i++) {
if (llDetectedKey(i) == owner) {
llRequestPermissions(owner, PERMISSION_CHANGE_LINKS);
}
}
}
run_time_permissions(integer perm) {
if (perm & PERMISSION_CHANGE_LINKS) {
rezObjects();
}
}
object_rez(key id) {
llCreateLink(id, TRUE);
}
} |
これを実行して、touch すると、目的の 30m x 20m の長方形の object ができます。Contents にある "square 10m" とスクリプトは、用済みなので削除します。これを、"rectangle 30x20-1" と名付けて、inventory に取り込んでおきます。 同様にして、左上に配置される 20m x 30m の "rectangle 20x30-2" を、さらに、左下の "rectangle 30x20-3", 右下の "rectangle 20x30-4" を作成します。 次に、中心となる "square 10m" を rez して、この中に、上記の 4つの大きな長方形の objects を入れます。これに、次のようなスクリプトを新規作成します。
makeLargeSquare() {
vector pos = llGetPos();
llRezAtRoot("rectangle 30x20-1", pos + < 10.0, 10.0, 0.0>, <0.0, 0.0, 0.0>, <0.0, 0.0, 0,0>, 0);
llRezAtRoot("rectangle 20x30-2", pos + <-10.0, 10.0, 0.0>, <0.0, 0.0, 0.0>, <0.0, 0.0, 0,0>, 0);
llRezAtRoot("rectangle 30x20-3", pos + <-10.0, -10.0, 0.0>, <0.0, 0.0, 0.0>, <0.0, 0.0, 0,0>, 0);
llRezAtRoot("rectangle 20x30-4", pos + < 10.0, -10.0, 0.0>, <0.0, 0.0, 0.0>, <0.0, 0.0, 0,0>, 0);
}
default {
state_entry() {
}
on_rez(integer param) {
makeLargeSquare();
}
} |
これを、"square 10m to 50m on rez" と名付けて、inventory に取り込みます。後は、この 10m square の prim を rez すると、まわりに 4つの大きな長方形が rez されて、50m の正方形ができます。ただし、link は、されていないので、独立した 5つの objects として、扱われます。 また、普通に rez してしまうと、地上に 50m squre ができてしまいます。そこで、もう一工夫します。別の適当な大きさの prim を作成して、上記の "square 10m to 50m on rez" と次のスクリプトをいれます。
default {
state_entry() {
}
touch_start(integer n) {
if (llDetectedKey(0) == llGetOwner()) {
vector p = llGetPos();
llRezObject("square 10m to 50m on rez", p + <0.0, 0.0, -1.0>,
<0.0, 0.0, 0.0>, <0.0, 0.0, 0,0>, 0);
}
}
} |
これに、座ってから、object の edit window から、position の Z に 4096.0 以下の大きな値を入力します。これで、座ったまま、一気に上空に移動するので、そこで touch すると、上記の snapshot のように、足下を中心に、50m 四方の正方形の床ができます。 2008-12-04 update(*) -> 20m Cube (#2 linked) - LSL #14 - SL #23 .. 17m !? Tags: programming, second_life
|
 |
 |
 |
 |
|
 |
 |


 |
|
 |
 |
 |
 |
|
 |
 |
土地を持っていないので、スクリプトを実行してみるには、sandbox で行う必要があります。ただし、地上は、ごちゃごちゃしていることが多いので、最近で は、 数千メートルの上空で作業しています。ただし、50m 四方の広い床があったとしても、間違って、落ちてしまう可能性もあり、Second Life 内のことなので、大事に至ることはありませんが、多少、面倒なことになります。このた め、 10m の立方体を作成したテクニックを応用して、30m 四方の床の回りに、高さ 10m のフェンスを作ってみました。今回も、smoke の(半)透明な texture を使ってみました。   これで落ちる心配をせずに、安心して作業することができるようになりました。 なお、Library にある Default Transparent Texture をセットしたところ、完全に透明になりました。どこまで床があるか全くわかりませんが、フ ェンスがあるので大丈夫です。ところが、この完全に透明なオブジェクトがマウスで選択 できなくなりました。このため、削除もできず、自動的に消滅するまで、放置しておくこ とになってしまいました。 Tags: programming, second_life
|
 |
 |
 |
 |
|
 |
 |



 |
|
 |
 |
 |
 |
|
 |
 |
昨日の写真では、10m x 10m x 1m の prim を使用しましたが、Second Life の制限により、10m 以上の prim を作成することはできません。しかし、複数の prim を link して、ひとつの object として扱うことができます。これを Linden Script で記述して、一辺が 30m の square を作成してみます。 まずは、prim をひとつ作成して、size を 10m x 10m x 1m とします。名前は、"square 10m" として、take して、自分の inventory に取り込みます。これを、rez して、この中に、同じ "square 10m" を入れ、次の script を作成します。
string square10 = "square 10m";
key owner;
integer count = 8;
list squares = [];
rezSquares() {
vector pos = llGetPos();
integer i;
for (i = -1; i < 2; i++) {
integer j;
for (j = -1; j < 2; j++) {
if (i != 0 || j!= 0) {
llRezAtRoot(square10, pos + <10.0 * (float)i, 10.0 * (float)j, 0.0>,
<0.0, 0.0, 0.0>, <0.0, 0.0, 0,0>, 0);
}
}
}
}
default {
state_entry() {
owner = llGetOwner();
}
touch_start(integer total_number) {
integer i = 0;
for ( ; i < total_number; i++) {
if (llDetectedKey(i) == owner) {
llRequestPermissions(owner, PERMISSION_CHANGE_LINKS);
}
}
}
run_time_permissions(integer perm) {
if (perm & PERMISSION_CHANGE_LINKS) {
rezSquares();
}
}
object_rez(key id) {
squares += id;
count --;
if (count == 0) {
integer i;
for (i = 0; i < 8; i++) {
llCreateLink(llList2Key(squares, i), TRUE);
}
}
}
} |
Root になる、もともとの prim の inventory にある 10m 四方の prim を、8回 rez して、自分のまわりに並べます。これだけでも、一応 30m 四方の square ができますが、移動したり、take などの操作では、別々の 9個の object として扱わなければならないので、面倒です。そこで、llCreateLink() で、周辺の prim を、中央の root prim に、link しています。Link を変更するためには、runtime permission が必要になるため、最初に、llRequestPermissions() で、owner に permission を要求しています。 なお、一定の距離以上(多分、10m 以上)離れていると、llRezAtRoot() や llRezObject(), また、llCreateLink() が失敗します。また、このときに、object の root position で計算しているのか、center position なのかで、状況が変わってきます。このため、上記のスクリプトでは、llRezAtR oot() を用いて、root position で object を rez したあとに、まとめて、link しています。小さな object を扱っている場合は、特に問題がない場合もありますが、このように大きな object を扱う場合は、注意が必要です。 昨日と同様に、30m square の object を 3776m の上空に浮かべて、記念写真をとりました。   Tags: programming, second_life
|
 |
 |
 |
 |
|
 |
 |




|
 |
 |