Newer
Older
monitord / lame-3.97 / frontend / .svn / text-base / brhist.c.svn-base
@root root on 23 Jan 2012 18 KB Migration from SVN revision 455
  1. /*
  2. * Bitrate histogram source file
  3. *
  4. * Copyright (c) 2000 Mark Taylor
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Library General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Library General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Library General Public
  17. * License along with this library; if not, write to the
  18. * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19. * Boston, MA 02111-1307, USA.
  20. */
  21.  
  22. /* $Id: brhist.c,v 1.46.2.1 2005/12/18 18:49:28 robert Exp $ */
  23.  
  24. #ifdef HAVE_CONFIG_H
  25. #include <config.h>
  26. #endif
  27.  
  28. #ifdef BRHIST
  29.  
  30. /* basic #define's */
  31.  
  32. #ifndef BRHIST_WIDTH
  33. # define BRHIST_WIDTH 14
  34. #endif
  35. #ifndef BRHIST_RES
  36. # define BRHIST_RES 14
  37. #endif
  38.  
  39.  
  40. /* #includes */
  41.  
  42. #ifdef STDC_HEADERS
  43. # include <stdlib.h>
  44. # include <string.h>
  45. #else
  46. # ifndef HAVE_STRCHR
  47. # define strchr index
  48. # define strrchr rindex
  49. # endif
  50. char *strchr(), *strrchr();
  51. # ifndef HAVE_MEMCPY
  52. # define memcpy(d, s, n) bcopy ((s), (d), (n))
  53. # define memmove(d, s, n) bcopy ((s), (d), (n))
  54. # endif
  55. #endif
  56.  
  57.  
  58. #if defined(HAVE_NCURSES_TERMCAP_H)
  59. # include <ncurses/termcap.h>
  60. #elif defined(HAVE_TERMCAP_H)
  61. # include <termcap.h>
  62. #elif defined(HAVE_TERMCAP)
  63. # include <curses.h>
  64. # if !defined(__bsdi__)
  65. # include <term.h>
  66. # endif
  67. #endif
  68.  
  69. #include "brhist.h"
  70.  
  71. #ifdef WITH_DMALLOC
  72. #include <dmalloc.h>
  73. #endif
  74.  
  75.  
  76. /* Structure holding all data related to the Console I/O
  77. * may be this should be a more global frontend structure. So it
  78. * makes sense to print all files instead with
  79. * printf ( "blah\n") with printf ( "blah%s\n", Console_IO.str_clreoln );
  80. */
  81.  
  82. Console_IO_t Console_IO;
  83.  
  84. static struct {
  85. int vbr_bitrate_min_index;
  86. int vbr_bitrate_max_index;
  87. int kbps[BRHIST_WIDTH];
  88. int hist_printed_lines;
  89. char bar_asterisk[512 + 1]; /* buffer filled up with a lot of '*' to print a bar */
  90. char bar_percent[512 + 1]; /* buffer filled up with a lot of '%' to print a bar */
  91. char bar_coded[512 + 1]; /* buffer filled up with a lot of ' ' to print a bar */
  92. char bar_space[512 + 1]; /* buffer filled up with a lot of ' ' to print a bar */
  93. } brhist;
  94.  
  95. static int
  96. calculate_index(const int *const array, const int len, const int value)
  97. {
  98. int i;
  99.  
  100. for (i = 0; i < len; i++)
  101. if (array[i] == value)
  102. return i;
  103. return -1;
  104. }
  105.  
  106. int
  107. brhist_init(const lame_global_flags * gf, const int bitrate_kbps_min,
  108. const int bitrate_kbps_max)
  109. {
  110. #ifdef HAVE_TERMCAP
  111. char term_buff[2048]; /* see 1) */
  112. const char *term_name;
  113. char *tp;
  114. char tc[10];
  115. int val;
  116. #endif
  117.  
  118. /* setup basics of brhist I/O channels */
  119. Console_IO.disp_width = 80;
  120. Console_IO.disp_height = 25;
  121. brhist.hist_printed_lines = 0;
  122. Console_IO.Console_fp = stderr;
  123. Console_IO.Error_fp = stderr;
  124. Console_IO.Report_fp = stderr;
  125.  
  126. setvbuf(Console_IO.Console_fp, Console_IO.Console_buff, _IOFBF,
  127. sizeof(Console_IO.Console_buff));
  128. /* setvbuf ( Console_IO.Error_fp , NULL , _IONBF, 0 ); */
  129.  
  130. #if defined(_WIN32) && !defined(__CYGWIN__)
  131. Console_IO.Console_Handle = GetStdHandle(STD_ERROR_HANDLE);
  132. #endif
  133.  
  134. strcpy(Console_IO.str_up, "\033[A");
  135.  
  136. #ifndef RH_HIST
  137. /* some internal checks */
  138. if (bitrate_kbps_min > bitrate_kbps_max) {
  139. fprintf(Console_IO.Error_fp,
  140. "lame internal error: VBR min %d kbps > VBR max %d kbps.\n",
  141. bitrate_kbps_min, bitrate_kbps_max);
  142. return -1;
  143. }
  144. if (bitrate_kbps_min < 8 || bitrate_kbps_max > 320) {
  145. fprintf(Console_IO.Error_fp,
  146. "lame internal error: VBR min %d kbps or VBR max %d kbps out of range.\n",
  147. bitrate_kbps_min, bitrate_kbps_max);
  148. return -1;
  149. }
  150. #endif
  151.  
  152. /* initialize histogramming data structure */
  153. lame_bitrate_kbps(gf, brhist.kbps);
  154. brhist.vbr_bitrate_min_index =
  155. calculate_index(brhist.kbps, BRHIST_WIDTH, bitrate_kbps_min);
  156. brhist.vbr_bitrate_max_index =
  157. calculate_index(brhist.kbps, BRHIST_WIDTH, bitrate_kbps_max);
  158.  
  159. if (brhist.vbr_bitrate_min_index >= BRHIST_WIDTH ||
  160. brhist.vbr_bitrate_max_index >= BRHIST_WIDTH) {
  161. fprintf(Console_IO.Error_fp,
  162. "lame internal error: VBR min %d kbps or VBR max %d kbps not allowed.\n",
  163. bitrate_kbps_min, bitrate_kbps_max);
  164. return -1;
  165. }
  166.  
  167. memset(brhist.bar_asterisk, '*', sizeof(brhist.bar_asterisk) - 1);
  168. memset(brhist.bar_percent, '%', sizeof(brhist.bar_percent) - 1);
  169. memset(brhist.bar_space, '-', sizeof(brhist.bar_space) - 1);
  170. memset(brhist.bar_coded, '-', sizeof(brhist.bar_space) - 1);
  171.  
  172. #ifdef HAVE_TERMCAP
  173. /* try to catch additional information about special console sequences */
  174.  
  175. if ((term_name = getenv("TERM")) == NULL) {
  176. fprintf(Console_IO.Error_fp,
  177. "LAME: Can't get \"TERM\" environment string.\n");
  178. return -1;
  179. }
  180. if (tgetent(term_buff, term_name) != 1) {
  181. fprintf(Console_IO.Error_fp,
  182. "LAME: Can't find termcap entry for terminal \"%s\"\n",
  183. term_name);
  184. return -1;
  185. }
  186.  
  187. val = tgetnum("co");
  188. if (val >= 40 && val <= 512)
  189. Console_IO.disp_width = val;
  190. val = tgetnum("li");
  191. if (val >= 16 && val <= 256)
  192. Console_IO.disp_height = val;
  193.  
  194. *(tp = tc) = '\0';
  195. tp = tgetstr("up", &tp);
  196. if (tp != NULL)
  197. strcpy(Console_IO.str_up, tp);
  198.  
  199. *(tp = tc) = '\0';
  200. tp = tgetstr("ce", &tp);
  201. if (tp != NULL)
  202. strcpy(Console_IO.str_clreoln, tp);
  203.  
  204. *(tp = tc) = '\0';
  205. tp = tgetstr("md", &tp);
  206. if (tp != NULL)
  207. strcpy(Console_IO.str_emph, tp);
  208.  
  209. *(tp = tc) = '\0';
  210. tp = tgetstr("me", &tp);
  211. if (tp != NULL)
  212. strcpy(Console_IO.str_norm, tp);
  213.  
  214. #endif /* HAVE_TERMCAP */
  215.  
  216. return 0;
  217. }
  218.  
  219. static int
  220. digits(unsigned number)
  221. {
  222. int ret = 1;
  223.  
  224. if (number >= 100000000) {
  225. ret += 8;
  226. number /= 100000000;
  227. }
  228. if (number >= 10000) {
  229. ret += 4;
  230. number /= 10000;
  231. }
  232. if (number >= 100) {
  233. ret += 2;
  234. number /= 100;
  235. }
  236. if (number >= 10) {
  237. ret += 1;
  238. }
  239.  
  240. return ret;
  241. }
  242.  
  243.  
  244. static void
  245. brhist_disp_line(int i, int br_hist_TOT, int br_hist_LR, int full, int frames)
  246. {
  247. char brppt[14]; /* [%] and max. 10 characters for kbps */
  248. int barlen_TOT;
  249. int barlen_LR;
  250. int ppt = 0;
  251. int res = digits(frames) + 3 + 4 + 1;
  252.  
  253. if (full != 0) {
  254. /* some problems when br_hist_TOT \approx br_hist_LR: You can't see that there are still MS frames */
  255. barlen_TOT = (br_hist_TOT * (Console_IO.disp_width - res) + full - 1) / full; /* round up */
  256. barlen_LR = (br_hist_LR * (Console_IO.disp_width - res) + full - 1) / full; /* round up */
  257. }
  258. else {
  259. barlen_TOT = barlen_LR = 0;
  260. }
  261.  
  262. if (frames > 0)
  263. ppt = (1000 * br_hist_TOT + frames / 2) / frames; /* round nearest */
  264.  
  265. sprintf(brppt, " [%*i]", digits(frames), br_hist_TOT);
  266.  
  267. if (Console_IO.str_clreoln[0]) /* ClearEndOfLine available */
  268. fprintf(Console_IO.Console_fp, "\n%3d%s %.*s%.*s%s",
  269. brhist.kbps[i], brppt,
  270. barlen_LR, brhist.bar_percent,
  271. barlen_TOT - barlen_LR, brhist.bar_asterisk,
  272. Console_IO.str_clreoln);
  273. else
  274. fprintf(Console_IO.Console_fp, "\n%3d%s %.*s%.*s%*s",
  275. brhist.kbps[i], brppt,
  276. barlen_LR, brhist.bar_percent,
  277. barlen_TOT - barlen_LR, brhist.bar_asterisk,
  278. Console_IO.disp_width - res - barlen_TOT, "");
  279.  
  280. brhist.hist_printed_lines++;
  281. }
  282.  
  283.  
  284. #ifdef RH_HIST
  285. static void
  286. progress_line(const lame_global_flags * gf, int full, int frames)
  287. {
  288. char rst[20] = "\0";
  289. int barlen_TOT = 0, barlen_COD = 0, barlen_RST = 0;
  290. int res = 1;
  291. float df = 0;
  292. unsigned int hour, min, sec;
  293. int fsize = lame_get_framesize(gf);
  294. int srate = lame_get_out_samplerate(gf);
  295.  
  296. if (full < frames) {
  297. full = frames;
  298. }
  299. if (srate > 0) {
  300. df = full - frames;
  301. df *= fsize;
  302. df /= srate;
  303. }
  304. hour = df / 3600;
  305. df -= hour * 3600;
  306. min = df / 60;
  307. df -= min * 60;
  308. sec = df;
  309. if (full != 0) {
  310. if (hour > 0) {
  311. sprintf(rst, "%*u:%02u:%02u", digits(hour), hour, min, sec);
  312. res += digits(hour) + 1 + 5;
  313. }
  314. else {
  315. sprintf(rst, "%02u:%02u", min, sec);
  316. res += 5;
  317. }
  318. /* some problems when br_hist_TOT \approx br_hist_LR: You can't see that there are still MS frames */
  319. barlen_TOT = (full * (Console_IO.disp_width - res) + full - 1) / full; /* round up */
  320. barlen_COD = (frames * (Console_IO.disp_width - res) + full - 1) / full; /* round up */
  321. barlen_RST = barlen_TOT - barlen_COD;
  322. if (barlen_RST == 0) {
  323. sprintf(rst, "%.*s", res - 1, brhist.bar_coded);
  324. }
  325. }
  326. else {
  327. barlen_TOT = barlen_COD = barlen_RST = 0;
  328. }
  329. if (Console_IO.str_clreoln[0]) { /* ClearEndOfLine available */
  330. fprintf(Console_IO.Console_fp, "\n%.*s%s%.*s%s",
  331. barlen_COD, brhist.bar_coded,
  332. rst, barlen_RST, brhist.bar_space, Console_IO.str_clreoln);
  333. }
  334. else {
  335. fprintf(Console_IO.Console_fp, "\n%.*s%s%.*s%*s",
  336. barlen_COD, brhist.bar_coded,
  337. rst, barlen_RST, brhist.bar_space,
  338. Console_IO.disp_width - res - barlen_TOT, "");
  339. }
  340. brhist.hist_printed_lines++;
  341. }
  342.  
  343.  
  344. static int
  345. stats_value(double x)
  346. {
  347. if (x > 0.0) {
  348. fprintf(Console_IO.Console_fp, " %5.1f", x);
  349. return 6;
  350. }
  351. /*
  352. else {
  353. fprintf( Console_IO.Console_fp, " " );
  354. return 6;
  355. }
  356. */
  357. return 0;
  358. }
  359.  
  360. static int
  361. stats_head(double x, const char *txt)
  362. {
  363. if (x > 0.0) {
  364. fprintf(Console_IO.Console_fp, txt);
  365. return 6;
  366. }
  367. /*
  368. else {
  369. fprintf( Console_IO.Console_fp, " " );
  370. return 6;
  371. }
  372. */
  373. return 0;
  374. }
  375.  
  376.  
  377. static void
  378. stats_line(double *stat)
  379. {
  380. int n = 1;
  381. fprintf(Console_IO.Console_fp, "\n kbps ");
  382. n += 12;
  383. n += stats_head(stat[1], " mono");
  384. n += stats_head(stat[2], " IS ");
  385. n += stats_head(stat[3], " LR ");
  386. n += stats_head(stat[4], " MS ");
  387. fprintf(Console_IO.Console_fp, " %% ");
  388. n += 6;
  389. n += stats_head(stat[5], " long ");
  390. n += stats_head(stat[6], "switch");
  391. n += stats_head(stat[7], " short");
  392. n += stats_head(stat[8], " mixed");
  393. n += fprintf(Console_IO.Console_fp, " %%");
  394. if (Console_IO.str_clreoln[0]) { /* ClearEndOfLine available */
  395. fprintf(Console_IO.Console_fp, "%s", Console_IO.str_clreoln);
  396. }
  397. else {
  398. fprintf(Console_IO.Console_fp, "%*s", Console_IO.disp_width - n, "");
  399. }
  400. brhist.hist_printed_lines++;
  401.  
  402. n = 1;
  403. fprintf(Console_IO.Console_fp, "\n %5.1f ", stat[0]);
  404. n += 12;
  405. n += stats_value(stat[1]);
  406. n += stats_value(stat[2]);
  407. n += stats_value(stat[3]);
  408. n += stats_value(stat[4]);
  409. fprintf(Console_IO.Console_fp, " ");
  410. n += 6;
  411. n += stats_value(stat[5]);
  412. n += stats_value(stat[6]);
  413. n += stats_value(stat[7]);
  414. n += stats_value(stat[8]);
  415. if (Console_IO.str_clreoln[0]) { /* ClearEndOfLine available */
  416. fprintf(Console_IO.Console_fp, "%s", Console_IO.str_clreoln);
  417. }
  418. else {
  419. fprintf(Console_IO.Console_fp, "%*s", Console_IO.disp_width - n, "");
  420. }
  421. brhist.hist_printed_lines++;
  422. }
  423. #endif
  424.  
  425. /* Yes, not very good */
  426. #define LR 0
  427. #define MS 2
  428.  
  429. void
  430. brhist_disp(const lame_global_flags * gf)
  431. {
  432. int i, lines = 0;
  433. int br_hist[BRHIST_WIDTH]; /* how often a frame size was used */
  434. int br_sm_hist[BRHIST_WIDTH][4]; /* how often a special frame size/stereo mode commbination was used */
  435. int st_mode[4];
  436. int bl_type[6];
  437. int frames; /* total number of encoded frames */
  438. int most_often; /* usage count of the most often used frame size, but not smaller than Console_IO.disp_width-BRHIST_RES (makes this sense?) and 1 */
  439. double sum = 0.;
  440. #ifdef RH_HIST
  441. double stat[9] = { 0 };
  442. int st_frames = 0;
  443. #endif
  444.  
  445. brhist.hist_printed_lines = 0; /* printed number of lines for the brhist functionality, used to skip back the right number of lines */
  446.  
  447. lame_bitrate_stereo_mode_hist(gf, br_sm_hist);
  448. lame_bitrate_hist(gf, br_hist);
  449. lame_stereo_mode_hist(gf, st_mode);
  450. lame_block_type_hist(gf, bl_type);
  451.  
  452. frames = most_often = 0;
  453. for (i = 0; i < BRHIST_WIDTH; i++) {
  454. frames += br_hist[i];
  455. sum += br_hist[i] * brhist.kbps[i];
  456. if (most_often < br_hist[i])
  457. most_often = br_hist[i];
  458. if (br_hist[i])
  459. ++lines;
  460. }
  461.  
  462. for (i = 0; i < BRHIST_WIDTH; i++) {
  463. int show = br_hist[i];
  464. #ifdef RH_HIST
  465. show = show && (lines > 1);
  466. #endif
  467. if (show
  468. || (i >= brhist.vbr_bitrate_min_index
  469. && i <= brhist.vbr_bitrate_max_index))
  470. brhist_disp_line(i, br_hist[i], br_sm_hist[i][LR], most_often,
  471. frames);
  472. }
  473. #ifdef RH_HIST
  474. for (i = 0; i < 4; i++) {
  475. st_frames += st_mode[i];
  476. }
  477. if (frames > 0) {
  478. stat[0] = sum / frames;
  479. stat[1] = 100. * (frames - st_frames) / frames;
  480. }
  481. if (st_frames > 0) {
  482. stat[2] = 0.0;
  483. stat[3] = 100. * st_mode[LR] / st_frames;
  484. stat[4] = 100. * st_mode[MS] / st_frames;
  485. }
  486. if (bl_type[5] > 0) {
  487. stat[5] = 100. * bl_type[0] / bl_type[5];
  488. stat[6] = 100. * (bl_type[1] + bl_type[3]) / bl_type[5];
  489. stat[7] = 100. * bl_type[2] / bl_type[5];
  490. stat[8] = 100. * bl_type[4] / bl_type[5];
  491. }
  492. progress_line(gf, lame_get_totalframes(gf), frames);
  493. stats_line(stat);
  494. #endif
  495. fputs("\r", Console_IO.Console_fp);
  496. fflush(Console_IO.Console_fp); /* fflush is ALSO needed for Windows! */
  497. }
  498.  
  499. void
  500. brhist_jump_back(void)
  501. {
  502. #if defined(_WIN32) && !defined(__CYGWIN__)
  503. if (GetFileType(Console_IO.Console_Handle) != FILE_TYPE_PIPE) {
  504. COORD Pos;
  505. CONSOLE_SCREEN_BUFFER_INFO CSBI;
  506.  
  507. GetConsoleScreenBufferInfo(Console_IO.Console_Handle, &CSBI);
  508. Pos.Y = CSBI.dwCursorPosition.Y - brhist.hist_printed_lines;
  509. Pos.X = 0;
  510. SetConsoleCursorPosition(Console_IO.Console_Handle, Pos);
  511. }
  512. #else
  513. while (brhist.hist_printed_lines-- > 0)
  514. fputs(Console_IO.str_up, Console_IO.Console_fp);
  515. #endif
  516. }
  517.  
  518.  
  519. void
  520. brhist_disp_total(const lame_global_flags * gf)
  521. {
  522. #ifndef RH_HIST
  523.  
  524. int i;
  525. int br_hist[BRHIST_WIDTH];
  526. int st_mode[4];
  527. int bl_type[6];
  528. int st_frames = 0;
  529. int br_frames = 0;
  530. double sum = 0.;
  531.  
  532. lame_stereo_mode_hist(gf, st_mode);
  533. lame_bitrate_hist(gf, br_hist);
  534. lame_block_type_hist(gf, bl_type);
  535.  
  536. for (i = 0; i < BRHIST_WIDTH; i++) {
  537. br_frames += br_hist[i];
  538. sum += br_hist[i] * brhist.kbps[i];
  539. }
  540.  
  541. for (i = 0; i < 4; i++) {
  542. st_frames += st_mode[i];
  543. }
  544.  
  545. if (0 == br_frames)
  546. return;
  547.  
  548. fprintf(Console_IO.Console_fp, "\naverage: %5.1f kbps", sum / br_frames);
  549.  
  550. /* I'm very unhappy because this is only printed out in VBR modes */
  551.  
  552. if (st_frames > 0) {
  553. if (st_mode[LR] > 0)
  554. fprintf(Console_IO.Console_fp, " LR: %d (%#5.4g%%)", st_mode[LR],
  555. 100. * st_mode[LR] / st_frames);
  556. else
  557. fprintf(Console_IO.Console_fp, " ");
  558. if (st_mode[MS] > 0)
  559. fprintf(Console_IO.Console_fp, " MS: %d (%#5.4g%%)", st_mode[MS],
  560. 100. * st_mode[MS] / st_frames);
  561. }
  562. fprintf(Console_IO.Console_fp, "\n");
  563.  
  564. if (bl_type[5] > 0) {
  565. extern int silent;
  566. if (silent <= -5 && silent > -10) {
  567. fprintf(Console_IO.Console_fp, "block type");
  568. fprintf(Console_IO.Console_fp, " long: %#4.3f",
  569. 100. * bl_type[0] / bl_type[5]);
  570. fprintf(Console_IO.Console_fp, " start: %#4.3f",
  571. 100. * bl_type[1] / bl_type[5]);
  572. fprintf(Console_IO.Console_fp, " short: %#4.3f",
  573. 100. * bl_type[2] / bl_type[5]);
  574. fprintf(Console_IO.Console_fp, " stop: %#4.3f",
  575. 100. * bl_type[3] / bl_type[5]);
  576. fprintf(Console_IO.Console_fp, " mixed: %#4.3f",
  577. 100. * bl_type[4] / bl_type[5]);
  578. fprintf(Console_IO.Console_fp, " (%%)\n");
  579. }
  580. else if (silent <= -10) {
  581. fprintf(Console_IO.Console_fp,
  582. "block types granules percent\n");
  583. fprintf(Console_IO.Console_fp, " long: % 10d % 8.3f%%\n",
  584. bl_type[0], 100. * bl_type[0] / bl_type[5]);
  585. fprintf(Console_IO.Console_fp, " start: % 10d % 8.3f%%\n",
  586. bl_type[1], 100. * bl_type[1] / bl_type[5]);
  587. fprintf(Console_IO.Console_fp, " short: % 10d % 8.3f%%\n",
  588. bl_type[2], 100. * bl_type[2] / bl_type[5]);
  589. fprintf(Console_IO.Console_fp, " stop: % 10d % 8.3f%%\n",
  590. bl_type[3], 100. * bl_type[3] / bl_type[5]);
  591. fprintf(Console_IO.Console_fp, " mixed: % 10d % 8.3f%%\n",
  592. bl_type[4], 100. * bl_type[4] / bl_type[5]);
  593. }
  594. }
  595. #else
  596. (void) gf;
  597. #endif
  598.  
  599. fflush(Console_IO.Console_fp);
  600. }
  601.  
  602. /*
  603. * 1)
  604. *
  605. * Taken from Termcap_Manual.html:
  606. *
  607. * With the Unix version of termcap, you must allocate space for the description yourself and pass
  608. * the address of the space as the argument buffer. There is no way you can tell how much space is
  609. * needed, so the convention is to allocate a buffer 2048 characters long and assume that is
  610. * enough. (Formerly the convention was to allocate 1024 characters and assume that was enough.
  611. * But one day, for one kind of terminal, that was not enough.)
  612. */
  613.  
  614. #endif /* ifdef BRHIST */