void CompressionTool::extractAndEncodeWAV(const char *outName, Common::File &input, AudioFormat compMode) { unsigned int length; char fbuf[2048]; size_t size; input.seek(-4, SEEK_CUR); length = input.readUint32LE(); length += 8; input.seek(-8, SEEK_CUR); /* Copy the WAV data to a temporary file */ Common::File f(outName, "wb"); while (length > 0) { size = input.read_noThrow(fbuf, length > sizeof(fbuf) ? sizeof(fbuf) : length); if (size <= 0) break; length -= (int)size; f.write(fbuf, size); } f.close(); /* Convert the WAV temp file to OGG/MP3 */ encodeAudio(outName, false, -1, tempEncoded, compMode); }
int main(int argc, char *argv[]) { GtkWidget *main_window, *scroll; GtkWidget *treeview; GtkTreeViewColumn *column; GtkCellRenderer *name_renderer, *size_renderer; GtkTreeStore *store; GtkTreeIter categories[14]; GValue value = { 0, }; gint offset; uint32 res_counts[14]; uint32 res_sizes[14]; int i; Common::File in; uint32 index_pos; uint32 pos, len; gtk_init(&argc, &argv); if (argc != 2) { printf("Usage: %s filename\n", argv[0]); return EXIT_FAILURE; } in.open(argv[1], "rb"); if (!in.isOpen()) { printf("Couldn't open %s for reading\n", argv[1]); return EXIT_FAILURE; } /* Create the main window, scrollable in both directions */ main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(main_window), "CLUster Explorer"); gtk_window_set_default_size(GTK_WINDOW(main_window), 400, 400); g_signal_connect(G_OBJECT(main_window), "destroy", G_CALLBACK(main_window_destroy_cb), NULL); scroll = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); /* Create the tree view */ for (i = 0; i < ARRAYSIZE(res_counts); i++) { res_counts[i] = 0; res_sizes[i] = 0; } store = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store), compare_items, NULL, NULL); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING); index_pos = in.readUint32LE(); in.seek(index_pos, SEEK_SET); for (;;) { GtkTreeIter iter; byte type; gchar *utf8_name; gchar name[34]; gchar *size; try { pos = in.readUint32LE(); len = in.readUint32LE(); } catch (...) { break; } size = make_size(len); index_pos = in.pos(); in.seek(pos, SEEK_SET); type = in.readByte(); in.readByte(); /* compType */ in.readUint32LE(); /* compSize */ in.readUint32LE(); /* decompSize */ in.read_noThrow(name, sizeof(name)); /* * We need to convert from Latin-1 to UTF-8. Otherwise the text * "CAFÉ" won't be displayed properly. */ utf8_name = g_convert(name, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL); if (!res_counts[type]) { gtk_tree_store_append(store, &categories[type], NULL); gtk_tree_store_set(store, &categories[type], NAME_COLUMN, getType(type), SIZE_COLUMN, "", TYPE_COLUMN, -1, POSITION_COLUMN, -1, LENGTH_COLUMN, -1, -1); } res_counts[type]++; res_sizes[type] += len; gtk_tree_store_append(store, &iter, &categories[type]); gtk_tree_store_set(store, &iter, NAME_COLUMN, utf8_name, SIZE_COLUMN, size, TYPE_COLUMN, type, POSITION_COLUMN, pos, LENGTH_COLUMN, len); in.seek(index_pos, SEEK_SET); } in.close(); for (i = 0; i < ARRAYSIZE(res_counts); i++) { if (res_counts[i]) { gchar size[80]; sprintf(size, "%s [%d]", make_size(res_sizes[i]), res_counts[i]); gtk_tree_store_set(store, &categories[i], SIZE_COLUMN, size, -1); } } treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE); g_signal_connect(G_OBJECT(treeview), "button-press-event", G_CALLBACK(tree_view_button_cb), argv[1]); /* The view now holds a reference. We can get rid of our own. */ g_object_unref(G_OBJECT(store)); name_renderer = gtk_cell_renderer_text_new(); size_renderer = gtk_cell_renderer_text_new(); g_value_init(&value, G_TYPE_FLOAT); g_value_set_float(&value, 1.0); g_object_set_property(G_OBJECT(size_renderer), "xalign", &value); gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW(treeview), -1, "Name", name_renderer, "text", NAME_COLUMN, NULL); offset = gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW(treeview), -1, "Size", size_renderer, "text", SIZE_COLUMN, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), offset - 1); gtk_tree_view_column_set_alignment(column, 1.0); gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(treeview)); gtk_container_add(GTK_CONTAINER(main_window), scroll); gtk_widget_show_all(GTK_WIDGET(main_window)); gtk_main(); return EXIT_SUCCESS; }
bool loadWAVFromStream(Common::File &stream, int &size, int &rate, byte &flags, uint16 *wavType, int *blockAlign_) { const uint32 initialPos = stream.pos(); byte buf[4+1]; buf[4] = 0; stream.read_noThrow(buf, 4); if (memcmp(buf, "RIFF", 4) != 0) { warning("getWavInfo: No 'RIFF' header"); return false; } uint32 wavLength = stream.readUint32LE(); stream.read_noThrow(buf, 4); if (memcmp(buf, "WAVE", 4) != 0) { warning("getWavInfo: No 'WAVE' header"); return false; } stream.read_noThrow(buf, 4); if (memcmp(buf, "fmt ", 4) != 0) { warning("getWavInfo: No 'fmt' header"); return false; } uint32 fmtLength = stream.readUint32LE(); if (fmtLength < 16) { // A valid fmt chunk always contains at least 16 bytes warning("getWavInfo: 'fmt' header is too short"); return false; } // Next comes the "type" field of the fmt header. Some typical // values for it: // 1 -> uncompressed PCM // 17 -> IMA ADPCM compressed WAVE // See <http://www.saettler.com/RIFFNEW/RIFFNEW.htm> for a more complete // list of common WAVE compression formats... uint16 type = stream.readUint16LE(); // == 1 for PCM data uint16 numChannels = stream.readUint16LE(); // 1 for mono, 2 for stereo uint32 samplesPerSec = stream.readUint32LE(); // in Hz uint32 avgBytesPerSec = stream.readUint32LE(); // == SampleRate * NumChannels * BitsPerSample/8 uint16 blockAlign = stream.readUint16LE(); // == NumChannels * BitsPerSample/8 uint16 bitsPerSample = stream.readUint16LE(); // 8, 16 ... // 8 bit data is unsigned, 16 bit data signed if (wavType != 0) *wavType = type; if (blockAlign_ != 0) *blockAlign_ = blockAlign; #if 0 printf("WAVE information:\n"); printf(" total size: %d\n", wavLength); printf(" fmt size: %d\n", fmtLength); printf(" type: %d\n", type); printf(" numChannels: %d\n", numChannels); printf(" samplesPerSec: %d\n", samplesPerSec); printf(" avgBytesPerSec: %d\n", avgBytesPerSec); printf(" blockAlign: %d\n", blockAlign); printf(" bitsPerSample: %d\n", bitsPerSample); #endif if (type != 1 && type != 2 && type != 17) { warning("getWavInfo: only PCM, MS ADPCM or IMA ADPCM data is supported (type %d)", type); return false; } if (blockAlign != numChannels * bitsPerSample / 8 && type != 2) { debug(0, "getWavInfo: blockAlign is invalid"); } if (avgBytesPerSec != samplesPerSec * blockAlign && type != 2) { debug(0, "getWavInfo: avgBytesPerSec is invalid"); } // Prepare the return values. rate = samplesPerSec; flags = 0; if (bitsPerSample == 8) // 8 bit data is unsigned flags |= Audio::Mixer::FLAG_UNSIGNED; else if (bitsPerSample == 16) // 16 bit data is signed little endian flags |= (Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN); else if (bitsPerSample == 4 && type == 17) // MS IMA ADPCM compressed. We decompress it flags |= (Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN); else if (bitsPerSample == 4 && type == 2) // MS ADPCM compressed. We decompress it flags |= (Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN); else { warning("getWavInfo: unsupported bitsPerSample %d", bitsPerSample); return false; } if (numChannels == 2) flags |= Audio::Mixer::FLAG_STEREO; else if (numChannels != 1) { warning("getWavInfo: unsupported number of channels %d", numChannels); return false; } // It's almost certainly a WAV file, but we still need to find its // 'data' chunk. // Skip over the rest of the fmt chunk. int offset = fmtLength - 16; do { stream.seek(offset, SEEK_CUR); if (stream.pos() >= int(initialPos + wavLength + 8)) { warning("getWavInfo: Cannot find 'data' chunk"); return false; } stream.read_noThrow(buf, 4); offset = stream.readUint32LE(); #if 0 printf(" found a '%s' tag of size %d\n", buf, offset); #endif } while (memcmp(buf, "data", 4) != 0); // Stream now points at 'offset' bytes of sample data... size = offset; return true; }