Fast scrambling courtesy of a C function.
[amarok_sonynw.git] / walkgirl / audiofile.rb
blobd627d258d87ede5fabd469ddcd1adca6003d0bef
1 ############################################################################
2 #    Copyright (C) 2008 by RafaƂ Rzepecki   #
3 #    divided.mind@gmail.com   #
4 #                                                                          #
5 #    This program is free software; you can redistribute it and#or modify  #
6 #    it under the terms of the GNU General Public License as published by  #
7 #    the Free Software Foundation; either version 2 of the License, or     #
8 #    (at your option) any later version.                                   #
9 #                                                                          #
10 #    This program is distributed in the hope that it will be useful,       #
11 #    but WITHOUT ANY WARRANTY; without even the implied warranty of        #
12 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
13 #    GNU General Public License for more details.                          #
14 #                                                                          #
15 #    You should have received a copy of the GNU General Public License     #
16 #    along with this program; if not, write to the                         #
17 #    Free Software Foundation, Inc.,                                       #
18 #    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             #
19 ############################################################################
21 require 'id3'
23 module NetworkWalkman
24   class AudioFile
25     MPEG_VERSION = [:v2_5, :reserved, :v2, :v1]
26     attr_accessor :length, :frames, :tags
27     attr_reader :filename, :slot
28     class FromDevice < AudioFile
29       attr_reader :encoding
30       def initialize(*args)
31         @length, @frames, @tags, @filename, @slot, @encoding = args
32       end
33       def scramble(outfile)
34         # noop
35       end
36     end
38     def self.open(filename)
39       File.open(filename) { |f|
40         begin
41           slot = filename.match("1([0-9a-f]{7})\.")[1].hex
42           tag_data = f.read(3072)
43           f.seek(0xc22)
44           encoding, _, length, frames = f.read(10).unpack("CCNN")
45           f.close
46           tag_data[0..4] = ["ID3", 4, 0].pack("a3CC")
47           tags = ID3::Tag2.new
48           tags.raw = tag_data
49           tags.parse!
50           tags.each { |key, tag|
51             begin
52               tags[key] = tag.recode(0)
53             rescue
54               begin # try harder to recode
55                 tag = tag.clone
56                 tag["text"] = tag["text"][0...(tag["text"].length-1)]
57                 tags[key] = tag.recode(0)
58               rescue
59               end
60             end
61           }
62           return FromDevice.new(length, frames, tags, filename, slot, encoding)
63         rescue
64           STDERR.puts("Corrupted file #{filename}")
65         end
66       }
67     end
69     def self.openAll(mount_point)
70       files = []
71       Dir[File.join([mount_point, 'omgaudio', '10f*'])].sort.each { |dir|
72         Dir[File.join([dir, "*.oma"])].sort.each do |filename|
73           af = AudioFile.open(filename)
74           files[af.slot-1] = af if af
75         end
76       }
77       files
78     end
80     def encoding
81       (mpeg_version << 6) |
82       (mpeg_layer   << 4) |
83       (bitrate_id       )
84     end
86     def save
87       File.open(filename, 'w+') {|outfile|
88         tag = ID3::Tag2.new
89         if tags # convert to ID3v2
90           tags.each { |key, value|
91             tag[key] = value
92             tag[key] = tag[key].recode(2) if tag[key]["text"]
93           }
94         end
95         tag = tag.dump
96         tag[0...10] = ["ea3", 3, 0x1776].pack("a3c@8n")
97         outfile.sysseek(0, IO::SEEK_SET)
98         outfile.syswrite [tag].pack("a3072")
99         # write out header
100         outfile.syswrite "EA3"
101         outfile.syswrite [2, 0, 0x60, 0xff, 0xfe, 1, 0x0f, 0x50, 0x00].pack("c5@9c4")
102         outfile.syswrite [0, 4, 0, 0, 0, 1, 2, 3, 0xc8, 0xd8, 0x36, 0xd8, 0x11, 0x22, 0x33, 0x44].pack("c*")
103         outfile.syswrite [0x03, 0x80, encoding, 10, length, frames, 0].pack("c4N3")
104         outfile.syswrite [0,0,0,0].pack("N4")
105         outfile.syswrite [0,0,0,0].pack("N4")
106         outfile.syswrite [0,0,0,0].pack("N4")
107         outfile.sysseek outfile.tell
108         scramble(outfile)
109       }
110     end
112     def initialize
113     end
114     def track_length
115       @length
116     end
117     def tags
118       @tags
119     end
120     def frame_count
121       @frames
122     end
123   end